package com.smile.cn.bean;

import com.smile.cn.entity.EMailServer;
import com.smile.cn.entity.MailAuthentication;
import com.smile.cn.entity.config.EMailConfig;
import com.sun.net.ssl.internal.ssl.Provider;
import java.io.File;
import java.security.Security;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class SendEmailBean {
	final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
	private MimeMessage mimeMsg = null;
	private MimeMultipart mp = null;
	private String messageid = "";

	/**
	 * major function for user
	 * 
	 * @param auth
	 * @param receivers
	 * @param copyTo
	 * @param bccTo
	 * @param title
	 * @param content
	 * @param attachs
	 * @param headers
	 * @return
	 * @throws Exception
	 */
	public boolean sendMail(MailAuthentication auth, List<String> receivers,
			List<String> ccs, List<String> bccs, String title, String content,
			List<String> attachs, Map<String, String> headers) throws Exception {
		this.createMessage(receivers, ccs, bccs, title, content, attachs,
				auth.getUserName(), headers);
		try {
			return this.send(auth);
		} catch (Exception e) {
			throw new Exception("send email failed", e);
		}
	}

	/**
	 * create email
	 * 
	 * @param receivers
	 * @param ccs
	 * @param bccs
	 * @param title
	 * @param content
	 * @param attachs
	 * @param from
	 * @param headers
	 * @throws Exception
	 */
	public void createMessage(List<String> receivers, List<String> ccs,
			List<String> bccs, String title, String content,
			List<String> attachs, String from, Map<String, String> headers)
			throws Exception {
		if (receivers == null || from == null || receivers.size() == 0) {
			throw new Exception(
					"createMessage field : receivers is null or from is null");
		}
		this.initMessage();
		this.setMimeHeader(headers);
		this.setFrom(from);
		this.setReceiver(receivers);
		this.setCc(ccs);
		this.setBcc(bccs);
		this.setSubject(title);
		this.setBody(content);
		this.setAttach(attachs);
		this.saveContent();
	}

	public boolean send(MailAuthentication _auth) throws Exception {
		EMailServer server = EMailConfig.getEMailServerByUser(_auth
				.getUserName());
		Properties props = this.getProperties(server);
		Transport transport = null;
		MailAuthentication auth = null;
		if ((server != null) && (server.isIssmtpauth())) {
			auth = _auth;
		}
		Session session = Session.getInstance(props, auth);
		session.setDebug(true);
		transport = session.getTransport("smtp");
		transport.connect();
		transport.sendMessage(this.mimeMsg, this.mimeMsg.getAllRecipients());
		transport.close();
		return true;
	}

	private Properties getProperties(EMailServer server) throws Exception {
		if (server == null) {
			throw new Exception("server is null");
		}
		Properties props = new Properties();
		if (server.isIssmtpauth())
			props.put("mail.smtp.auth", "true");
		else {
			props.put("mail.smtp.auth", "false");
		}
		props.put("mail.smtp.host", server.getSmtpserver());
		props.put("mail.Transport.protocol", "smtp");
		props.put("mail.smtp.port", server.getSmtpport());

		if ("ssl".equalsIgnoreCase(server.getSecurityprotocol())) {
			Security.addProvider(new Provider());
			props.put("mail.smtp.socketFactory.class",
					"javax.net.ssl.SSLSocketFactory");
			props.put("mail.smtp.socketFactory.port", server.getSmtpport());
			props.put("mail.smtp.socketFactory.fallback", "false");
		} else if ("tls".equalsIgnoreCase(server.getSecurityprotocol())) {
			props.put("mail.smtp.starttls.enable", "true");
		}
		return props;
	}

	/**
	 * initialise the meail
	 * 
	 * @throws Exception
	 */
	public void initMessage() throws Exception {
		Session session = null;
		this.mimeMsg = new MimeMessage(session);
		this.mp = new MimeMultipart();
		this.mimeMsg.saveChanges();
		this.messageid = this.mimeMsg.getMessageID().substring(1,
				this.mimeMsg.getMessageID().indexOf(".JavaMail"));
	}

	/**
	 * set the email mime header
	 * 
	 * @param headers
	 * @throws Exception
	 */
	public void setMimeHeader(Map<String, String> headers) throws Exception {
		if (headers == null || headers.size() == 0) {
			headers = new HashMap<String, String>();
			headers.put("X-Mailer", "Jsmail  0.1");
		}
		for (Map.Entry<String, String> header : headers.entrySet()) {
			this.mimeMsg.addHeader(header.getKey(), header.getValue());
		}
	}

	/**
	 * set subject of the email
	 * 
	 * @param mailSubject
	 * @return
	 * @throws Exception
	 */
	public String setSubject(String mailSubject) throws Exception {
		if (mailSubject == null) {
			mailSubject = "";
		}
		this.mimeMsg.setSubject(MimeUtility.encodeText(mailSubject, "utf-8",
				"B"));
		return null;
	}

	/**
	 * set the email body
	 * 
	 * @param mailBody
	 * @throws Exception
	 */
	public void setBody(String mailBody) throws Exception {
		if (mailBody == null) {
			mailBody = "";
		}
		List<String> fileList = new ArrayList<String>();
		// String body = this.changeDir(fileList, mailBody);
		String body = mailBody;
		MimeMultipart mp1 = new MimeMultipart("alternative");
		MimeBodyPart plainPart = new MimeBodyPart();
		plainPart.setText(mailBody, "utf-8");

		MimeBodyPart htmlPart = new MimeBodyPart();
		htmlPart.setContent(body, "text/html;charset=utf-8");
		htmlPart.setHeader("Content-Transfer-Encoding", "base64");

		mp1.addBodyPart(plainPart);
		mp1.addBodyPart(htmlPart);
		MimeBodyPart text = new MimeBodyPart();
		text.setContent(mp1);
		this.mp.addBodyPart(text);
		this.mp.setSubType("alternative");
		if (fileList.size() > 0) {
			MimeBodyPart part3 = new MimeBodyPart();
			for (int i = 0; i < fileList.size(); i++) {
				DataSource source = new FileDataSource(new File(
						((String) fileList.get(i)).toString()));
				part3.setDataHandler(new DataHandler(source));
				part3.setFileName(MimeUtility.encodeText(source.getName(),
						"UTF-8", "B"));
				part3.setContentID("<Part" + i + "." + this.messageid + ">");
				part3.setDisposition("inline");
				this.mp.addBodyPart(part3);
			}
			this.mp.setSubType("related");
		}
	}

	/**
	 * set email attachment
	 * 
	 * @param list
	 * @throws Exception
	 */
	public void setAttach(List<String> list) throws Exception {
		if (list == null || list.size() == 0) {
			return;
		}
		if (list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				BodyPart bp = new MimeBodyPart();
				File file = new File(list.get(i));
				if (!file.isFile()) {
					throw new Exception("this file is not file");
				} else {
					DataSource source = new FileDataSource(file);
					bp.setDataHandler(new DataHandler(source));
					bp.setFileName(MimeUtility.encodeText(source.getName(),
							"UTF-8", "B"));
					bp.setDisposition("attachment");
					this.mp.addBodyPart(bp);
				}
			}
			this.mp.setSubType("mixed");
		}
	}

	/**
	 * set addresser
	 * 
	 * @param from
	 * @throws Exception
	 */
	public void setFrom(String from) throws Exception {
		if (from == null) {
			throw new Exception("addresser is null");
		}
		InternetAddress addresser = new InternetAddress(from);
		// String personal = "";
		// addresser.setPersonal(personal, "utf-8");
		this.mimeMsg.setFrom(addresser);
	}

	/**
	 * set reveiver
	 * 
	 * @param receiver
	 * @throws Exception
	 */
	public void setReceiver(List<String> receiver) throws Exception {
		if (receiver == null || receiver.size() == 0) {
			return;
		}
		InternetAddress[] address = new InternetAddress[receiver.size()];
		for (int i = 0; i < receiver.size(); i++) {
			address[i] = new InternetAddress((String) receiver.get(i));
		}
		this.mimeMsg.addRecipients(Message.RecipientType.TO, address);
	}

	/**
	 * set cc
	 * 
	 * @param copyto
	 * @throws Exception
	 */
	public void setCc(List<String> copyto) throws Exception {
		if (copyto == null || copyto.size() == 0) {
			return;
		}
		if (copyto.size() > 0) {
			InternetAddress[] address = new InternetAddress[copyto.size()];
			for (int i = 0; i < copyto.size(); i++) {
				address[i] = new InternetAddress((String) copyto.get(i));
			}
			this.mimeMsg.addRecipients(Message.RecipientType.CC, address);
		}
	}

	/**
	 * set bcc
	 * 
	 * @param bcc
	 * @throws Exception
	 */
	public void setBcc(List<String> bcc) throws Exception {
		if (bcc == null || bcc.size() == 0) {
			return;
		}
		if (bcc.size() > 0) {
			InternetAddress[] address = new InternetAddress[bcc.size()];
			for (int i = 0; i < bcc.size(); i++) {
				address[i] = new InternetAddress((String) bcc.get(i));
			}
			this.mimeMsg.addRecipients(Message.RecipientType.BCC, address);
		}
	}

	/**
	 * save the email body
	 * 
	 * @throws Exception
	 */
	public void saveContent() throws Exception {
		this.mimeMsg.setSentDate(new Date());
		this.mimeMsg.setContent(this.mp);
		this.mimeMsg.saveChanges();
	}

	public MimeMessage getMimeMsg() {
		return this.mimeMsg;
	}

	/**
	 * remove the img element's src value of html content and change it as cid
	 * 
	 * @param fileList
	 * @param content
	 * @return
	 */
	private String changeDir(List<String> fileList, String content) {
		Document doc = Jsoup.parse(content);
		Elements media = doc.select("img");
		if (media == null || media.size() == 0) {
			return content;
		}
		for (int i = 0; i < media.size(); i++) {
			Element a = media.get(i);
			String filename = a.attr("src");
			fileList.add(filename);
			a.removeAttr("src");
			a.attr("src", "cid:Part" + i + "." + this.messageid);
		}
		return doc.html();
	}
}
